// ======================================= GENERAL =======================================

/**
 * save canvas to PNG picture
 * @param canvasId: string type
 * @param sel: Selection type of crop.js
 */
function saveToPng(canvasId, sel){
	var oCanvas = null, pic = null;
	if ($("#" + canvasId + "_mask").css("display") == "none") {
		oCanvas = document.getElementById(canvasId);
	}else{
		var cs = document.getElementById(canvasId);
		var imageData = cs.getContext("2d").getImageData(sel.x, sel.y, sel.x+ sel.w, sel.y + sel.h);
		oCanvas = document.createElement('canvas');
		oCanvas.width = sel.w;
		oCanvas.height = sel.h;
		oCanvas.getContext("2d").putImageData(imageData, 0,0);
	}
	pic = oCanvas.toDataURL('image/png');
	
	if(oCanvas.getContext("2d")){
		if (navigator.appName == 'Microsoft Internet Explorer'){
			var win = window.open("about:blank", "_blank");
			win.document.write("<img id='pic' src ='"+pic+"'>");
		}else{
			window.open(pic);
		}
	}
}


/**
 * @param canvasId: string type
 */
function setCrop(canvasId){
	$("#"+ canvasId+"_cancel").removeAttr("disabled"); 		//disable button
	$("#"+canvasId+"_mask").css("display","inherit"); 	//show mask
}

/**
 * @param canvasId: string type
 */
function cancelCrop(canvasId){
//	$("#"+ canvasId+"_cancel").attr("disabled","disabled"); //enable button
	$("#"+canvasId+"_mask").css("display","none");	//hide mask
}

// ======================================= 1D chart ======================================
var chart_1D;
var canvas_1D;

function draw1DLayout() {

	chart_1D.draw();

	canvas_1D = document.getElementById("canvas_1D");
	canvas_1D.addEventListener("mousedown", D1_mouseDown, false);
	canvas_1D.addEventListener("mouseup", D1_mouseUp, false);
	canvas_1D.addEventListener("mouseout", D1_mouseUp, false);

	canvas_1D.addEventListener('DOMMouseScroll', D1_wheel, false);
	canvas_1D.addEventListener("mousewheel", D1_wheel, false);
}

function Gaussian(x, a, b, c) {
	return a * Math.exp(-(x - b) * (x - b) / (2 * c * c));
}

function D1_mouseDown(e) {
	var xcanvas = $(this).offset().left;
	var ycanvas = $(this).offset().top;
	if (e.pageX > xcanvas + offsetX + widthFloat / 2 && e.pageX < xcanvas + this.width - offsetX - widthFloat / 2
			&& e.pageY > ycanvas + offsetY + heightFloat / 2
			&& e.pageY < ycanvas + this.height - offsetY - heightFloat / 2) {
		dragok = true;
		preMouseX = e.pageX;
		preMouseY = e.pageY;
		canvas_1D.onmousemove = D1_mouseMove;
	}
	;
}

function D1_mouseUp(e) {
	dragok = false;
	canvas_1D.onmousemove = null;
}

function D1_mouseMove(e) {
	if (dragok) {
		chart_1D.setMove(e.pageX - preMouseX, e.pageY - preMouseY);
		preMouseX = e.pageX;
		preMouseY = e.pageY;
	}
}

function D1_wheel(event) {
	var delta = 0;
	if (!event) /* For IE. */
		event = window.event;
	if (event.wheelDelta) { /* IE/Opera. */
		delta = event.wheelDelta / 120;
	} else if (event.detail) { // Mozilla
		delta = -event.detail / 3;
	}
	if (delta)
		D1_wheelHandle(delta);
	/**
	 * Prevent default actions caused by mouse wheel. That might be ugly, but we
	 * handle scrolls somehow anyway, so don't bother here..
	 */
	if (event.preventDefault)
		event.preventDefault();
	event.returnValue = false;
}

function D1_wheelHandle(y) {
	chart_1D.scale(Math.pow(0.8, y));
}

function clear1D() {
	chart_1D.clean();
}

function D1_chart(canvasId) {
	var id = canvasId;
	var canvasData = null;

	var context = null;

	var canvas = document.getElementById(id);
	var width = $(canvas).attr("width");
	var height = $(canvas).attr("Height");

	var x_scaleNum = 40;
	var y_scaleNum = 25;

	var x0_val = -20;
	var xm_val = 20;
	var y0_val = -1;
	var ym_val = 2;

	var x0 = 0;
	var xm = 0;
	var y0 = 0;
	var ym = 0;

	this.draw = function() {

		this.inialNum();

		this.createBackgroud();
		this.createCoordniate();
		this.renderFunction();
	};

	this.clean = function() {
		if (context != null) {
			context.clearRect(0, 0, width, height);

			// weird clearRect only doesn't work
			context.beginPath();
			context.closePath();
		}
	};

	this.scale = function(s) {
		x0_val = Math.round(x0_val * s * 10000) / 10000;
		xm_val = Math.round(xm_val * s * 10000) / 10000;
		y0_val = Math.round(y0_val * s * 10000) / 10000;
		ym_val = Math.round(ym_val * s * 10000) / 10000;
		var x_d = xm_val - x0_val;
		var y_d = ym_val - y0_val;
		if (x_d > 10000 || x_d < 0.001 || y_d > 10000 || y_d < 0.001) {
			return;
		}
		this.clean();
		this.draw();
	};

	this.setMove = function(mouseX, mouseY) {
		x0_val = x0_val - mouseX * (xm_val - x0_val) / (xm - x0);
		xm_val = xm_val - mouseX * (xm_val - x0_val) / (xm - x0);
		y0_val = y0_val - mouseY * (ym_val - y0_val) / (ym - y0);
		ym_val = ym_val - mouseY * (ym_val - y0_val) / (ym - y0);

		this.clean();
		this.draw();
	};

	this.inialNum = function() {
		context = document.getElementById(id).getContext("2d");

		widthFloat = (width - 2 * offsetX) % x_scaleNum;
		heightFloat = (height - 2 * offsetY) % y_scaleNum;
		x0 = offsetX + widthFloat / 2;
		xm = width - widthFloat / 2 - offsetX;
		y0 = height - heightFloat / 2 - offsetY;
		ym = offsetY + heightFloat / 2;
	};

	this.createBackgroud = function() {

		context.strokeStyle = "#000";
		context.lineWidth = 1;
		context.lineCap = "round"; // round, square, butt

		var gradient = context.createLinearGradient(x0 + 20, y0, x0, ym);
		gradient.addColorStop(0, "#eee");
		gradient.addColorStop(1, "#fff");
		context.fillStyle = gradient;

		context.fillRect(x0, ym, xm - x0, y0 - ym);
	};

	this.createCoordniate = function() {

		context.strokeStyle = "#000";
		context.lineWidth = 1;
		context.lineCap = "round"; // round, square, butt

		// word
		context.fillStyle = "#000";
		context.textAlign = "center";
		context.font = "bold 12pt Calibri";
		context.fillText("Network Layout of 2D Guassian Function", width / 2, offsetY - 10);
		context.font = "11pt Calibri";
		context.fillText("X-Coordinator", width / 2, y0 + offsetY);

		context.save();
		context.translate(x0, y0);
		context.rotate(-Math.PI / 2);
		context.textBaseline = "middle";
		context.textAlign = "center";
		context.fillText("Y-Coordinator", height / 2 - offsetX, -offsetX + 4);
		context.restore();

		// border line
		context.moveTo(x0, y0);
		context.lineTo(x0, ym);
		context.moveTo(x0, y0);
		context.lineTo(xm, y0);
		context.moveTo(x0, ym);
		context.lineTo(xm, ym);
		context.moveTo(xm, y0);
		context.lineTo(xm, ym);

		context.textBaseline = "middle";

		var stepY = (ym_val - y0_val) * 5 / y_scaleNum;
		if (stepY >= 1 && stepY < 10) {
			stepY = Math.round(stepY);
		} else if (stepY >= 0.1 && stepY < 1) {
			stepY = Math.round(stepY * 10) / 10;
		} else if (stepY >= 10 && stepY < 100) {
			stepY = Math.round(stepY / 10) * 10;
		} else if (stepY >= 0.01 && stepY < 0.1) {
			stepY = Math.round(stepY * 100) / 100;
		} else if (stepY >= 100 && stepY < 1000) {
			stepY = Math.round(stepY / 100) * 100;
		} else if (stepY >= 0.001 && stepY < 0.01) {
			stepY = Math.round(stepY * 1000) / 1000;
		} else if (stepY >= 1000 && stepY < 10000) {
			stepY = Math.round(stepY / 1000) * 1000;
		} else if (stepY >= 0.0001 && stepY < 0.001) {
			stepY = Math.round(stepY * 10000) / 10000;
		}

		// y scale number
		for ( var i = Math.ceil(y0_val / stepY) * stepY; i <= ym_val; i = i + stepY) {
			context.fillText(Math.round(i * 10000) / 10000, x0 - 16, yc(i));

			context.moveTo(x0 - 5, yc(i));
			context.lineTo(x0 + 5, yc(i));
		}

		// y coordinator
		for ( var i = Math.ceil(y0_val / stepY) * stepY; i < ym_val; i = i + stepY / 5) {
			context.moveTo(x0 - 2, yc(i));
			context.lineTo(x0 + 2, yc(i));
		}

		for ( var i = Math.ceil(y0_val / stepY) * stepY; i > y0_val; i = i - stepY / 5) {
			context.moveTo(x0 - 2, yc(i));
			context.lineTo(x0 + 2, yc(i));
		}

		// x scale number
		var stepX = (xm_val - x0_val) * 5 / x_scaleNum;
		if (stepX >= 1 && stepX < 10) {
			stepX = Math.round(stepX);
		} else if (stepX >= 0.1 && stepX < 1) {
			stepX = Math.round(stepX * 10) / 10;
		} else if (stepX >= 10 && stepX < 100) {
			stepX = Math.round(stepX / 10) * 10;
		} else if (stepX >= 0.01 && stepX < 0.1) {
			stepX = Math.round(stepX * 100) / 100;
		} else if (stepX >= 100 && stepX < 1000) {
			stepX = Math.round(stepX / 100) * 100;
		} else if (stepX >= 0.001 && stepX < 0.01) {
			stepX = Math.round(stepX * 1000) / 1000;
		} else if (stepX >= 1000 && stepX < 10000) {
			stepX = Math.round(stepX / 1000) * 1000;
		} else if (stepX >= 0.001 && stepX < 0.01) {
			stepX = Math.round(stepX * 1000) / 1000;
		}

		for ( var i = Math.ceil(x0_val / stepX) * stepX; i <= xm_val; i = i + stepX) {
			context.fillText(Math.round(i * 10000) / 10000, xc(i), y0 + 18);

			context.moveTo(xc(i), y0 - 5);
			context.lineTo(xc(i), y0 + 5);
		}

		// x coordinator
		for ( var i = Math.ceil(x0_val / stepX) * stepX; i < xm_val; i = i + stepX / 5) {
			context.moveTo(xc(i), y0 - 2);
			context.lineTo(xc(i), y0 + 2);
		}

		for ( var i = Math.ceil(x0_val / stepX) * stepX; i > x0_val; i = i - stepX / 5) {
			context.moveTo(xc(i), y0 - 2);
			context.lineTo(xc(i), y0 + 2);
		}

		context.stroke();

		dotL = 12;
		canvasData = context.getImageData(0, 0, width, height);
		// dotted line
		for ( var i = Math.ceil(x0_val); i <= xm_val; i = i + stepX) {
			for ( var x = y0; x >= ym; x = x - dotL) {
				drawPixel(xc(i), x, 0, 0, 0, 64);
				drawPixel(xc(i), x + 1, 0, 0, 0, 64);
				drawPixel(xc(i), x + 2, 0, 0, 0, 64);
			}
			;
		}

		pixelStroke(context, canvasData);
	};

	this.renderFunction = function(f) {
		var first = true;
		context.beginPath();

		var h = 0;
		var parameters = new Array();

		var rows = $('#gene-table').getGridParam('selarrrow');
		for ( var i = 0; i < rows.length; i++) {
			row = $('#gene-table').getRowData(rows[i]);
			parameters[i] = {
				'a' : row['Height'],
				'b' : row['X Position'],
				'c' : row['X Width']
			};
			h = h + parseFloat(row['Height']);
		}

		var ymax = 0;
		for ( var x = -10; x <= 10; x += (xm_val - x0_val) / (xm - x0)) {
			var y = 0;
			for (i = 0; i < parameters.length; i++) {
				y = y + Gaussian(x, parameters[i]['a'], parameters[i]['b'], parameters[i]['c']);
				if (y > ymax)
					ymax = y;
			}
			if (y >= y0_val && y < ym_val && x > x0_val && x <= xm_val) {
				if (first) {
					context.moveTo(xc(x), yc(y));
					first = false;
				} else {
					context.lineTo(xc(x), yc(y));
				}
			} else {
				first = true;
			}
		}
		// context.closePath();
		context.lineWidth = 4;
		var gradient = context.createLinearGradient(0, yc(ymax), 0, yc(0));
		gradient.addColorStop(1, 'blue');
		gradient.addColorStop(0.7, 'green');
		gradient.addColorStop(0.3, 'yellow');
		gradient.addColorStop(0, 'red');
		context.fillStyle = gradient;
		context.strokeStyle = gradient;
		context.stroke();
	};

	/**
	 * put a point into canvas data
	 * 
	 * @param x x coordinate
	 * @param y y coordinate
	 * @param a transparency
	 */
	function drawPixel(x, y, r, g, b, a) {
		x = Math.round(x);

		// 4 - r g b a
		var index = (x + y * width) * 4;

		canvasData.data[index + 0] = r;
		canvasData.data[index + 1] = g;
		canvasData.data[index + 2] = b;
		canvasData.data[index + 3] = a;
	}

	/**
	 * drawing pixel to canvas
	 * 
	 * @param context: canvas context
	 * @param canvasData:must be canvas getImageData(0, 0,
	 *            canvasWidth,canvasHeight)
	 */
	function pixelStroke(context, canvasData) {
		context.putImageData(canvasData, 0, 0);
	}

	/**
	 * Returns the physical x-coordinate of a logical x-coordinate:
	 */
	function xc(x) {
		return (x - x0_val) / (xm_val - x0_val) * (xm - x0) + x0;
	}

	/**
	 * Returns the physical y-coordinate of a logical y-coordinate:
	 */
	function yc(y) {
		return (y - y0_val) / (ym_val - y0_val) * (ym - y0) + y0;
	};
};

